/**
 * Guiseppe Javascript client
 */
 
function Giuseppe()
{
  this.page = "";
  this.projects = [];
  this.defaultPage = "projects";
  this.contentId = "#page-content";
  this.scriptsId = "#page-scripts";
  this._waitCounter = 0;
  this._scheduled = [];
  
  this.initialize = function() {
    var gsp = this;
    $(document).ready(function(){gsp._init.call(gsp)});
  }
  
  this._init = function() {
    this.reloadPage();
  }
  
  // Manipulates semaphore while waiting for server responses
  this.waiting = function(num) {
    this._waitCounter += num;
    
    if (this._waitCounter == 0) {
      this._stopSpinner();
      this._runScheduledTasks();
    }
    else
      this._startSpinner();
      
    return this._waitCounter;
  }
  
  // Rotate the logo during waiting
  this._startSpinner = function() {
    if (this._spinnerTimer)
      return;
    
    var angle = 0;
    var gsp = this;
    var callback = function() {
      angle = (angle + 10) % 360;
      $("#logo").rotate(angle);
    };
    
    this._spinnerTimer = setInterval(callback, 30);
  }
  
  // Stop spinner if no pending requests
  this._stopSpinner = function() {
    $("#logo").rotate(0);
    clearInterval(this._spinnerTimer);
    this._spinnerTimer = null;
  }
  
  // Process all task waiting for server responses
  this._runScheduledTasks = function() {
    var task;
    while (task = this._scheduled.pop())
      task[0].call(task[1]);
  }
  
  // Schedule function when all responses are received
  this.scheduleTask = function(fn, ctx) {
    if (!ctx)
      ctx = this;
    if (fn)
      this._scheduled.push([fn, ctx]);
  }
  
  // Display modal window with message
  this.errorMessage = function(msg) {
    alert("Error: " + msg);
  };
  
  this.alertMessage = function(msg) {
    var html = '<div class="alert-message warning">';
    html += '<a class="close" href="#">×</a>';
    html += '<p>'+ msg +'</p>';
    html += '</div>';
    
    $(this.contentId).prepend($(html));
    $(".alert-message").alert();
  };
  
  // Refresh current URL
  this.reloadPage = function() {
    var page = (location.hash) ? location.hash.slice(1) : this.defaultPage;
    this.selectMenuItem(page);
    this.refreshProjects();
    
    // Load page after data is received
    this.scheduleTask(function() {
       this.loadPage(page);
    });
  };
  
  // Delete actual content
  this.clearPage = function() {
    $(this.contentId).html("");
  };
  
  // Load new partial and replace section content
  this.loadPage = function(page) {
    if (this.projects.length == 0)
      return;
    
    this.request('partial', {name: page}, function(data) {
      this.page = page;
      $(this.contentId).html(data);
      //~ $(this.scriptsId).html('<script src="js/'+ page +'.js"></script>');
      $.getScript('js/' + page + '.js', function() {
        loader();
      });
    });
  };
  
  // Set active menu item class to selected
  this.selectMenuItem = function(page) {
    $("li.active").removeClass("active");
    $("a[href=#" + page + "]").parent("li").addClass("active");
  };

  // Call new HTTP request on server
  this.request = function(name, params, handler, errHandler) {
    var gsp = this;
    gsp.waiting(1);
    
    $.get(name, params, function(resp) {
      if (resp.status == "OK") {
        if (handler)
          handler.call(gsp, resp.data);
      }
      else if (typeof errHandler != "undefined")
        errHandler.call(gsp, resp.status);
      else
        gsp.errorMessage(resp.status);
        
      gsp.waiting(-1);
    });
  };

  // Refresh the project list
  this.refreshProjects = function() {
    this.request("project", {a: "list"}, function(data) {
      this.projects = data;
      var divider = $("#projects_list .divider");
      $("#projects_list .project").remove();
      
      // No projects
      if (data.length == 0) {
        this.clearPage();
        this.alertMessage("<b>No project available.</b> Add new from top-right menu.");
        return;
      }
      // No project selected
      else if (!this.getSelectedProject()) {
        // Select first one
        this.projects[0].selected = true;
        this.request("project", {"a": "select", "name": this.projects[0].name});
      }
      
      for (var i in data) {
        var project = data[i];
        var elm = $('<li><a href="javascript:null" class="project">' + project.name + '</a></li>');
        divider.before(elm);
        
        if (project.selected)
          $("#selected_project").html(project.name);
      }
    });
  };
  
  // Load selected project
  this.selectProject = function(name) {
    this.request("project", {"a": "select", "name": name}, function() {
      this.reloadPage();
    });
  };
  
  // Return name of selected project
  this.getSelectedProject = function() {
    for (var i in this.projects)
      if (this.projects[i].selected)
        return this.projects[i].name;
    return null;
  };
  
  // Clone remote repository
  this.startCloning = function(name, url) {
    this.request("clone", "clear_status");
    this.request("clone", {name: name, url: url}, this.updateCloneProgress);
  };
  
  // Modal window with cloning status
  this.updateCloneProgress = function() {
    $("#clone_progressbar").progressbar();
    $("#clone_progress_msg").html("Initializing project...");
    
    var DONE = 128;
    var messages = {
      4: "Counting objects",
      8: "Compressing objects",
      32: "Receiving objects",
      64: "Resolving deltas",
      128: "Finishing"
    };
    
    this.request("clone", "status", function(state) {
      var tm = this.timer(this.updateCloneProgress, 1000);
      if (!state)
        return;
      
      var op = state.op_code & 0xfc;
      var msg = (messages[op] || "") + "... " + state.cur_count;
      var percents = 0;
      
      if (state.max_count != "") {
        percents = 100 * parseInt(state.cur_count) / parseInt(state.max_count);
        msg += " / " + state.max_count;
      }
      
      $("#clone_progressbar").progressbar({value: percents});
      $("#clone_progress_msg").html(msg);
      
      // Cloning finished
      if (op == DONE) {
        clearTimeout(tm);
        this.finishCloning();
      }
    });
  };
  
  // Update window with success message
  this.finishCloning = function() {
    $("#win_clone_progress h3").html("Cloning finished");
    $("#clone_progressbar").progressbar({value: 100});
    $("#clone_progress_msg").html("<strong>Done.</strong>");
    $("#win_clone_progress_btn_ok").removeClass("hidden");
    
    this.refreshProjects();
    this.scheduleTask(function() {
      this.reloadPage();
    });
  };
  
  // Set timer with event
  this.timer = function(fn, time) {
    var gsp = this;
    return setTimeout(function(){ fn.call(gsp); }, time);
  }
  
  // Convert timestamp to date and viceversa
  this.date = function(val) {
    if (typeof val == "number")
      return $.fn.datepicker.defaults.format(new Date(val * 1000));
    else
      return parseInt($.fn.datepicker.defaults.parse(val).getTime() / 1000);
  };
}